#include "fxcc/core/audio/openal/Source.h"

using namespace fxcc;
using namespace fxcc::audio::openal;

Source::Source(const Desc& desc)
    :fxcc::audio::common::Source(desc)
{
    m_Available = Init();
    
}

bool Source::Init()
{
    switch (m_Desc.m_Type)
    {
    case Desc::Type::_Wav_:
        return InitWav();
    case Desc::Type::_Ogg_:
        return InitOgg();
    default:
        return false;
    }
}

bool Source::InitWav()
{

    auto wavFile = std::make_shared<fxcc::audio::common::WavFile>(m_Desc.m_WavPath);

    if (!wavFile)
    {
        return false;
    }
    if (wavFile->m_Available)
    {
        Create();
        BufferData(wavFile->GetAlFormat(), (const short*)wavFile->Data(), wavFile->DataSize(), wavFile->SampleRate());
    }

    return wavFile->m_Available;

}

bool Source::InitOgg()
{
    auto oggFile = std::make_shared<fxcc::audio::common::OggFile>(m_Desc.m_OggPath);

    if (!oggFile)
    {
        return false;
    }
    if (oggFile->m_Available)
    {
        Create();
        BufferData(oggFile->GetAlFormat(), oggFile->Data(), oggFile->DataSize(), oggFile->SampleRate());
    }
    return oggFile->m_Available;
}

void Source::Restart() const
{
    Stop();
    Play();
}

void Source::Create()
{
    alGenSources(1, &m_Source);
    alGenBuffers(1, &m_Buffer);
}

void Source::BufferData(int format, const short* data, int size, int freq)
{
    // Fill the m_Buffer with audio data
    alBufferData(m_Buffer, format, data, size, freq);
    // Associate the m_Buffer with the m_Source
    alSourcei(m_Source, AL_BUFFER, m_Buffer);
}

void Source::Play()const
{
    // Play the sound
    alSourcePlay(m_Source);
}

void Source::Pause()const
{
    alSourcePause(m_Source);
}

void Source::Stop() const
{
    alSourceStop(m_Source);

}
void Source::WaitEnd()
{
    while (GetState() == AL_PLAYING);
}

int Source::GetInt(int param)
{
    int res = 0;
    alGetSourcei(m_Source, param, &res);
    return res;
}

int Source::GetState()
{
    return this->GetInt(AL_SOURCE_STATE);
}

float Source::GetFloat(int param)
{
    float res = 0.0f;
    alGetSourcef(m_Source, param, &res);
    return res;
}

void Source::SetInt(int param, int value)
{
    alSourcei(m_Source, param, value);
}

void Source::SetFloat(int param, float value)
{
    alSourcef(m_Source, param, value);

}

float Source::GetGain()
{
    return GetFloat(AL_GAIN);
}

void Source::SetGain(float gain)
{
    SetFloat(AL_GAIN, gain);
}

void Source::SetVec3(int param, float x, float y, float z)
{
    alSource3f(m_Source, param, x, y, z);
}

void Source::GetVec3(int param, float& x, float& y, float& z)
{
    alGetSource3f(m_Source, param, &x, &y, &z);

}

void Source::SetIVec3(int param, int x, int y, int z)
{
    alSource3i(m_Source, param, x, y, z);
}

void Source::GetIVec3(int param, int& x, int& y, int& z)
{
    alGetSource3i(m_Source, param, &x, &y, &z);
}

void Source::SetLooping(bool v)
{
    SetInt(AL_LOOPING, v);
}

void Source::Delete()
{
    if (m_Source)
        alDeleteSources(1, &m_Source);
    if (m_Buffer)
        alDeleteBuffers(1, &m_Buffer);
}

Source::~Source()
{
    Delete();
}